﻿#include "platform_link_impl.h"

namespace link_util {

PlatformLinkImpl::~PlatformLinkImpl() {
    UnInit();
}

bool PlatformLinkImpl::Init()
{
    UnInit();

    // 初始化knet的管道
    loop = knet_loop_create();
    connector = knet_loop_create_channel(loop, 1024, 1024 * 256); 

    if ( !connector || !loop )
    {
        return false;
    }

    // 设置connector
    knet_channel_ref_set_cb(connector, ConnectCb);
    knet_channel_ref_set_ptr(connector, reinterpret_cast<void*>(this));

    // 初始化rpc
    rpc_impl = std::make_shared<rpc::RpcImpl>();
    if ( !rpc_impl )
    {
        return false;
    }

    rpc_impl->initialize(&logger);
    return true;
}

void PlatformLinkImpl::UnInit()
{
    if (rpc_impl) {
        rpc_impl->deinitialize();
        rpc_impl.reset();
    }
    
    if ( trans )
    {
        trans = std::shared_ptr<PlatformTrans>(nullptr);
    }

    if ( connector )
    {
        knet_channel_ref_close(connector);
        connector = nullptr;
    }

    if ( loop )
    {
        knet_loop_destroy(loop);
        loop = nullptr;
    }
}

bool PlatformLinkImpl::Connect(const std::string &ip, std::uint32_t port)
{
    if ( !connector )
    {
        return false;
    }

    return (error_ok == knet_channel_ref_connect(connector, ip.c_str(), port, 5));
}

void PlatformLinkImpl::Update()
{
    if ( loop )
    {
        knet_loop_run_once(loop);
    }

    if ( rpc_impl )
    {
        rpc_impl->update();
    }
}

rpc::RpcImpl* PlatformLinkImpl::GetRpcImpl()
{
    if ( !rpc_impl )
    {
        return nullptr;
    }
    return rpc_impl.get();
}

rpc::Rpc* PlatformLinkImpl::GetRpc()
{
    if ( !rpc_impl )
    {
        return nullptr;
    }
    return dynamic_cast<rpc::Rpc*>(rpc_impl.get());
}

void PlatformLinkImpl::MakeTransport()
{
    if ( !connector )
    {
        return;
    }

    trans = std::make_shared<PlatformTrans>(connector);
}

std::shared_ptr<rpc::Transport> PlatformLinkImpl::GetTransport()
{
    return std::dynamic_pointer_cast<rpc::Transport>(trans);
}

void PlatformLinkImpl::ConnectCb(kchannel_ref_t* channel, knet_channel_cb_event_e e)
{
    if ( e & channel_cb_event_connect )
    {
        PlatformLinkImpl* link = reinterpret_cast<PlatformLinkImpl*>(knet_channel_ref_get_ptr(channel));
        if ( !link ) {
            return;
        }
        link->MakeTransport();
    }
    else if (e & channel_cb_event_recv) {
        PlatformLinkImpl* link = reinterpret_cast<PlatformLinkImpl*>(knet_channel_ref_get_ptr(channel));
        if ( !link ) {
            return;
        }

        rpc::RpcImpl* rpc_impl = link->GetRpcImpl();
        if ( !rpc_impl )
        {
            return;
        }

        std::shared_ptr<rpc::Transport> trans = link->GetTransport();
        rpc_impl->onMessage(trans);
    }
}

void PlatformLinkImpl::CoroStart(const coroutine::CoroEntry& entry) {
    // ::coro_start(entry);
}

}